package au.com.darkside.XServer.Xext;

import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.Log;

import au.com.darkside.XServer.Pixmap;
import au.com.darkside.XServer.Drawable;
import java.util.*;

public class ShapeRegion
{
	public final Region _region;
	Bitmap bm;
	int width;
	Vector<Rect> mainArray;
	int WIDTH_THRESHOLD;
	int HEIGHT_THRESHOLD;
	int RMSERROR_THRESHOLD;
	
	/**
	 * Constructor.
	 *
	 * @param id	The pixmap's ID.
	 * @param xServer	The X server.
	 * @param client	The client issuing the request.
	 * @param screen	The screen.
	 * @param width	The pixmap width.
	 * @param height	The pixmap height.
	 * @param depth	The pixmap depth.
	 */
	public ShapeRegion (
	) {
		_region=new Region();
		
	}
	
	public ShapeRegion ( Pixmap p)
	{
		Drawable dr=p.getDrawable();
		int height=dr.getHeight();
		width=dr.getWidth();
		//dr.setBackgroundColor(0xffffffff);
		bm=dr.getBitmap();
		//Log.e("ShapeRegion","hasAlpha:"+Boolean.toString(bm.hasAlpha()));
		int[] pixels=new int[width*height];
		bm.getPixels(pixels,0,width,0,0,width,height);
		int p00=bm.getPixel(0,0);
		int pmid=p00;
		for(int i=0;i<height;i+=5)
		{
			for(int j=0;j<width;j+=5)
			{
				pmid|=bm.getPixel(j,i);
			}
		}
		/*Log.e("ShapeRegion","depth:"+Integer.toString(depth));
		Log.e("ShapeRegion","drDepth:"+Integer.toString(drDepth));
		Log.e("ShapeRegion","height:"+Integer.toString(height));
		Log.e("ShapeRegion","width:"+Integer.toString(width));
		Log.e("ShapeRegion","p00:"+Integer.toHexString(p00));
		Log.e("ShapeRegion","pmid:"+Integer.toHexString(pmid));*/
		doQuadding(new Rect(0,0,width,height),1);
		_region=new Region();
		for(Rect temp : mainArray)
			_region.op(temp,Region.Op.UNION);
		/*if(_region.isComplex())
			Log.e("shapeRegion","complex!");
		Rect bounds2=_region.getBounds();
		if(bounds2!=null){
			Log.e("shapeRegion","xF:"+Integer.toString(bounds2.left));
			Log.e("shapeRegion","yF:"+Integer.toString(bounds2.top));
			Log.e("shapeRegion","x2F:"+Integer.toString(bounds2.right));
			Log.e("shapeRegion","y2F:"+Integer.toString(bounds2.bottom));
		}*/
	}

	public ShapeRegion(Vector<Rect> rects)
	{
		_region=new Region();
		/*Rect bounds=_region.getBounds();
		if(bounds!=null){
		Log.e("shapeRegion","xO:"+Integer.toString(bounds.left));
		Log.e("shapeRegion","yO:"+Integer.toString(bounds.top));
		Log.e("shapeRegion","x2O:"+Integer.toString(bounds.right));
		Log.e("shapeRegion","y2O:"+Integer.toString(bounds.bottom));
		}*/
		Iterator<Rect> iter=rects.iterator();
		Rect temp;
		Log.e("shapeRegion","REcts:"+Integer.toString(rects.size()));
		while(iter.hasNext()){
			temp=(Rect)iter.next();
			/*Log.e("shapeRegion","x:"+Integer.toString(temp.left));
			Log.e("shapeRegion","y:"+Integer.toString(temp.top));
			Log.e("shapeRegion","x2:"+Integer.toString(temp.right));
			Log.e("shapeRegion","y2:"+Integer.toString(temp.bottom));*/
			_region.op(temp,Region.Op.UNION);
		}
		/*if(_region.isComplex())
			Log.e("shapeRegion","complex!");
		bounds=_region.getBounds();
		if(bounds!=null){
			Log.e("shapeRegion","xF:"+Integer.toString(bounds.left));
			Log.e("shapeRegion","yF:"+Integer.toString(bounds.top));
			Log.e("shapeRegion","x2F:"+Integer.toString(bounds.right));
			Log.e("shapeRegion","y2F:"+Integer.toString(bounds.bottom));
		}*/
	}
	
	public void doQuadding(Rect mainRect,int sizeLowLimit)
	{
		mainArray = new Vector<Rect>();

		RMSERROR_THRESHOLD = 1;
		WIDTH_THRESHOLD = sizeLowLimit;
		HEIGHT_THRESHOLD = sizeLowLimit;

		quadRecurse( mainRect ); // *** RECURSE ***

		//Log.e("ShapeRegion","Total rects: " + mainArray.size() );
	}
	
	public void quadRecurse( Rect rect ) {
		//Log.e("ShapeRegion","quadRecurse");
		double rms=isDivisible( rect );
		if ( rms==0 )
		{
			mainArray.add( rect );
			//Log.e("mainArray.size",Integer.toString(mainArray.size()));
			return;
		}
		if (rms==1)
				return;
		
		Vector<Rect> newRects = quadDivide( rect ); // partition rect
		
		for (int i = 0; i < newRects.size(); i++)
			quadRecurse(newRects.elementAt(i));
	}

	private Vector<Rect> quadDivide(Rect rect)
	{
		int[] pixArray=new int[rect.width()*rect.height()];
		bm.getPixels(pixArray,0,rect.width(),rect.left,rect.top,rect.width(),rect.height());
		
		
// Get the visual "center of gravity" of the image
		double[] cg = getCG( pixArray, rect.width() );

		/*cg[0] = (cg[0] + .5) * .5;
		cg[1] = (cg[1] + .5) * .5;
		cg[0] = 1.0 - cg[0];
		cg[1] = 1.0 - cg[1];*/

		int centerx = ( (int)(cg[0] * rect.width()));
		centerx += rect.left;
		int centery = ( (int)(cg[1] * rect.height()));
		centery += rect.top;

		Vector<Rect> temp=new Vector<Rect>();
		/*Log.e("rect.left",Integer.toString(rect.left)+"-"+Integer.toString(rect.top));
		Log.e("rect.left",Integer.toString(centerx)+"-"+Integer.toString(rect.top));
		Log.e("rect.left",Integer.toString(rect.right)+"-"+Integer.toString(rect.top));
		Log.e("rect.left",Integer.toString(rect.left)+"-"+Integer.toString(centery));
		Log.e("rect.left",Integer.toString(centerx)+"-"+Integer.toString(centery));
		Log.e("rect.left",Integer.toString(rect.right)+"-"+Integer.toString(centery));
		Log.e("rect.left",Integer.toString(rect.left)+"-"+Integer.toString(rect.bottom));
		Log.e("rect.left",Integer.toString(centerx)+"-"+Integer.toString(rect.bottom));
		Log.e("rect.left",Integer.toString(rect.right)+"-"+Integer.toString(rect.bottom));*/
		temp.add(new Rect(rect.left, rect.top, centerx, centery));
		// UL
		temp.add(new Rect(rect.left, centery, centerx, rect.bottom));
		// LL
		temp.add(new Rect(centerx, rect.top, rect.right, centery));
		// UR
		temp.add(new Rect(centerx, centery, rect.right, rect.bottom));
		// LR
		
		return temp;
	}

	private double isDivisible(Rect rect)
	{
		/*Log.e("rect.left",Integer.toString(rect.left));
		Log.e("rect.top",Integer.toString(rect.top));
		Log.e("rect.width",Integer.toString(rect.width()));
		Log.e("rect.height",Integer.toString(rect.height()));*/
		if (rect.width() < WIDTH_THRESHOLD || rect.height() < HEIGHT_THRESHOLD)
			return 1;
		int[] pixArray=new int[rect.width()*rect.height()];
		bm.getPixels(pixArray,0,rect.width(),rect.left,rect.top,rect.width(),rect.height()); //getPixArrayFromRect( rect );
		//Log.e("getPixels","successful!");
		double rms = getRMSError( pixArray );
		//Log.e("rms",Double.toString(rms));

		return rms;
	}

	private double getRMSError(int[] pixArray)
	{
		double sum=0;
		for (int i=0;i<pixArray.length;i++)
			if(pixArray[i]==0xff000000)
				sum++;
		sum/=pixArray.length;
		//Log.e("ShapeRegion","sum:"+Integer.toString(sum));
		return sum;
	}
	
	
	// Get the visual center-of-gravity of a pixel array.
	// Pass the array and the raster width.
	public static double [] getCG(int [] pix, int w)
	{
		double[] a={0.5,0.5};
		return a;
		/*
		double intensity = 0;
		//int red = 0;
		//int green = 0;
		int blue = 0;
		double [] cg = { 0,0 };
		double averageIntensity = 0;
		int pvalue = 0;

		for (int i = 0; i < pix.length; i++ )
		{
			pvalue = pix[i];
			//red = ((pvalue >> 16) & 255);
			//green = ((pvalue >> 8) & 255);
			blue = pvalue & 255;
			intensity = ((double)(blue));
			averageIntensity += intensity;
			cg[0] += intensity * (i % w);
			cg[1] += intensity * (i / w);
		}

		if(cg[0]!=0)
			cg[0] /= averageIntensity;
		if(cg[1]!=0)
			cg[1] /= averageIntensity;
		if(w!=0)
			cg[0] /= w;
		if(w!=0)
			cg[1] /= pix.length/w;
		return cg;*/
	}
}
